Estos fragmentos de imágenes están tratados digitalmente para perder el detalle de esas zonas. Los efectos utilizados suelen ser el difuminado y el pixelado. Los dos son similares, pero en esta práctica nos centraremos en el pixelado de imágenes.
También, en otras ocasiones, el pixelado puede ser un efecto estético que se busca. Por ejemplo, podríamos querer transformar una imagen de Mario Bros y Luigi para que nos recordase más a la estética original de Nintendo.
O puede ser un recurso artístico.
En esta práctica queremos desarrollar las funciones necesarias para poder pixelar una imagen. En las secciones siguientes te explicaremos todo lo necesario para saber cómo hacer el pixelado y te daremos algunos ejemplos.
Las imágenes están compuestas de píxeles y cada píxel almacena un valor numérico que codifica el color. En la siguiente imagen puedes ver una zona aumentada de una fotografía y los píxeles que se encuentran en esa zona.
Para imágenes en blanco y negro este valor es un único número, pero para imágenes en color cada píxel contiene una terna de valores. Vamos a suponer que estamos trabajando con imágenes en blanco y negro y que el rango de valores de cada píxel es de 0 a 255. La imagen siguiente muestra los valores de la matriz de valores asociada a la zona de la imagen destacada con un pequeño recuadro blanco en el retrovisor.
Básicamente, el pixelado consiste en hacer que la imagen parezca que tiene unos bloques constituyentes mayores. Para ello, hay que hacer que todos los valores de una submatriz tomen el mismo valor. Volviendo al ejemplo de la imagen anterior, el del coche, el pixelado podría sustituir todos los valores de la matriz del fragmento del retrovisor por un único valor, por ejemplo, el valor medio de todos ellos. Pero la elección del valor de sustitución para los elementos de la submatriz puede ser otro, podríamos asignar a todos los valores de la sumatriz del ejemplo el mínimo de los valores que aparecen en la submatriz, o el máximo...
A continuación te mostramos una imagen y el efecto que provocamos al elegir como valor de sustitución para el pixelado el valor medio de los elementos de las submatrices, el valor mínimo y el valor máximo, respectivamente.
Pero una cuestión esencial es que también necesitamos saber cuál es la dimensión de las submatrices que deseamos considerar. Esto nos dará lo grueso que es el pixelado. Por ejemplo, no es lo mismo pixelar con una matriz 4x4 que con 15x15. A continuación puedes ver una imagen y el resultado de pixelar utilizando dimensiones 5x5, 15x15 y 30x30. Todas ellas con el valor medio de los puntos que componen las submatrices.
Como hemos visto en el apartado anterior, para poder pixelar una imagen necesitamos varios parámetros: obviamente una imagen, el tamaño de la submatriz, y el modo que utilizaremos para hacer la unificación de valores.
Concretando, lo que deseamos es que programes una función que dada una imagen devuelva una nueva imagen pixelada. La función tiene que llamarse pixelate(img, (pixel_width, pixel_height), mode)
y tiene que devolver una nueva imagen con el resultado del pixelado. Los parámetros de la función son:
img
, una imagen que suponemos es en blanco y negro;
(pixel_width, pixel_height)
, una tupla con dos valores enteros positivos que indican el tamaño del pixelado resultante. Lo normal es que estos números sean menores que las medidas de la imagen pero la función tiene que devolver un resultado en cualquier caso, incluso si son mayores. Si el tamaño de la imagen no es múltiplo del tamaño del pixelado, algunos cuadrados resultantes tendrán un tamaño menor que (pixel_width, pixel_height)
. Estos cuadrados más pequeños estarán situados en el borde derecho e inferior de la imagen, como se puede observar en la sección de Ejemplos gráficos. Dicho de otra forma, el pixelado comenzará siempre por el extremo superior izquierdo de la imagen, es decir por las coordenadas (0,0).
mode
, una cadena de caracteres indicando el modo del pixelado: escribiremos "mean"
en la llamada de la función si queremos calcular el valor medio; "min"
para calcular el mínimo y "max"
para calcular el máximo. Puesto que los valores de los píxeles son siempre enteros entre 0 y 255, todas las operaciones tienen que ser con números enteros y con aritmética entera, es decir, si aparecen decimales a la hora de calcular el valor medio utilizaremos únicamente su parte entera.
Veamos algunos ejemplos de los resultados de la función pixelate
con algunas imágenes.
Comenzamos con una imagen muy sencilla. Tiene unas dimensiones de 200x200 píxeles y unos escaques o casillas de 100x100 píxeles.
Supongamos que img
es una variable que tiene la imagen anterior. Veamos el resultado de las siguientes llamadas a la función pixelate
.
pixelate(img, (200, 200), 'mean')
El resultado es único bloque del mismo tamaño que la imagen (200x200) con el valor medio de la imagen entera, un valor gris medio de 127.
pixelate(img, (200, 200), 'min')
En este caso, como tomamos el mínimo de los valores, el cero.
pixelate(img, (200, 200), 'max')
Y en este último caso el valor máximo y por tanto el 255 de la zona blanca.
pixelate(img, (110, 110), 'max')
En este ejemplo, como estamos considerando bloques de 110x110 píxeles, con el máximo de los valores, sólo el cuadrado inferior derecho de 90x90 se mantiene de color negro. Observad que el tamaño de imagen no es múltiplo del tamaño de pixelado, por lo que los cuadrados más pequeños están en el borde derecho e inferior: el cuadrado superior derecho tiene tamaño 90x110, el inferior izquierdo 110x90 y el inferior derecho 90x90.
Seguimos con una imagen muy simétrica. Tiene unas dimensiones de 200x200 píxeles y unos escaques o casillas cuadradas de 10x10 píxeles.
Hay un montón de llamadas a la función pixelate que dan como resultado la misma imagen. Supongamos que img
es una variable que tiene la imagen anterior, todas las llamadas siguientes devolverían exactamente la misma imagen de partida:
pixelate(img, (10, 10), 'mean')
pixelate(img, (5, 5), 'max')
pixelate(img, (2, 2), 'min')
pixelate(img, (1, 1), 'mean')
Pero no siempre es así, por ejemplo pixelate(img, (11, 11), 'mean')
devuelve esta imagen:
otras llamadas interesantes con su resultados son estas:
pixelate(img, (15, 15), 'mean')
pixelate(img, (50, 50), 'mean')
Por supuesto, las dimensiones de los bloques de píxeles no tienen porqué ser siempre cuadrados. Aquí van unos ejemplos con dimensiones rectangulares.
pixelate(img, (10, 25), 'mean')
pixelate(img, (25, 10), 'mean')
El problema propuesto no es demasido difícil. De forma opcional os proponemos algunas extensiones interesantes: